use crate::ast::*;
use crate::error::{CompilerError, Result};
use inkwell::types::{BasicType, BasicTypeEnum};
use inkwell::values::{BasicMetadataValueEnum, BasicValueEnum};
use inkwell::AddressSpace;
use crate::llvm_backend::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {


    /// Generate method call expression
    pub(in crate::llvm_backend) fn generate_method_call_expression(
        &mut self,
        method_call: &MethodCallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Look up the method function
        let method_name = &method_call.method;

        // Special handling for Result methods
        if let Expression::Variable(var_name) = &*method_call.object {
            if let Some(Type::Result(result_type)) = self.variable_type_map.get(var_name) {
                // This is a Result method call
                // Clone result_type to avoid borrow checker issues
                let result_type_clone = result_type.clone();
                let result_value = self.generate_expression(&method_call.object)?;
                return self.generate_result_method_call(
                    method_name,
                    result_value,
                    &result_type_clone,
                    &method_call.arguments,
                    &method_call.location,
                );
            }

            if let Some(Type::Option(option_type)) = self.variable_type_map.get(var_name) {
                // This is an Option method call
                let option_type_clone = option_type.clone();
                let option_value = self.generate_expression(&method_call.object)?;
                // For mutable methods (take, replace), we need to pass the variable name
                if method_name == "take" || method_name == "replace" {
                    return self.generate_option_method_call_with_var(
                        method_name,
                        option_value,
                        &option_type_clone,
                        &method_call.arguments,
                        &method_call.location,
                        Some(var_name),
                    );
                } else {
                    return self.generate_option_method_call(
                        method_name,
                        option_value,
                        &option_type_clone,
                        &method_call.arguments,
                        &method_call.location,
                    );
                }
            }
        }

        if let Some(object_type) = self.infer_expression_type(&method_call.object) {
            if let Type::Reference(ref_type) = &object_type {
                if let Some(trait_name) =
                    self.trait_name_from_type(&ref_type.referenced_type)
                {
                    return self.generate_trait_object_method_call(
                        &trait_name,
                        method_call,
                    );
                }
            } else if let Type::Rc(rc_type) = &object_type {
                if method_call.method == "downgrade" {
                    return self.generate_rc_downgrade_method_call(rc_type, method_call);
                }
                if let Some(trait_name) =
                    self.trait_name_from_type(&rc_type.inner_type)
                {
                    return self.generate_rc_trait_method_call(
                        &trait_name,
                        method_call,
                    );
                }
            } else if let Type::Weak(weak_type) = &object_type {
                if method_call.method == "lock" {
                    return self.generate_weak_lock_method_call(weak_type, method_call);
                }
            }
        }

        // Special handling for slice methods
        if method_name == "push" || method_name == "append" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.push() or slice.append() method call
                    return self.generate_slice_push_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for slice.pop() method
        if method_name == "pop" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.pop() method call
                    return self.generate_slice_pop_method(var_name);
                }
            }
        }

        // Special handling for slice.remove(index) method
        if method_name == "remove" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.remove(index) method call
                    return self.generate_slice_remove_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for slice.insert(index, value) method
        if method_name == "insert" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.insert(index, value) method call
                    return self.generate_slice_insert_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for slice.len() method
        if method_name == "len" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.len() method call
                    return self.generate_slice_len_method(var_name);
                }
            }
        }

        // Special handling for slice.cap() method
        if method_name == "cap" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.cap() method call
                    return self.generate_slice_cap_method(var_name);
                }
            }
        }

        // Special handling for slice.is_empty() method
        if method_name == "is_empty" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.is_empty() method call
                    return self.generate_slice_is_empty_method(var_name);
                }
            }
        }

        // Special handling for slice.reserve(n) method
        if method_name == "reserve" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.reserve(n) method call
                    return self.generate_slice_reserve_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for slice.contains(value) method
        if method_name == "contains" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.contains(value) method call
                    return self.generate_slice_contains_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for slice.extend(other_slice) method
        if method_name == "extend" {
            // Check if the object is a slice variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Vec(_)) = self.variable_type_map.get(var_name) {
                    // This is slice.extend(other_slice) method call
                    return self.generate_slice_extend_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.len() method - returns Unicode character count
        if method_name == "len" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.len() method call
                    return self.generate_string_len_method(var_name);
                }
            }
        }

        // Special handling for string.bytes_len() method - returns byte length
        if method_name == "bytes_len" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.bytes_len() method call
                    return self.generate_string_bytes_len_method(var_name);
                }
            }
        }

        // Special handling for string.is_empty() method - returns bool
        if method_name == "is_empty" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.is_empty() method call
                    return self.generate_string_is_empty_method(var_name);
                }
            }
        }

        // Special handling for string.join(vector) method - joins a vector of strings
        if method_name == "join" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.join(vector) method call
                    return self.generate_string_join_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.repeat(n) method - repeats the string n times
        if method_name == "repeat" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.repeat(n) method call
                    return self.generate_string_repeat_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.contains(substring) method - checks if string contains substring
        if method_name == "contains" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.contains(substring) method call
                    return self.generate_string_contains_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.starts_with(prefix) method - checks if string starts with prefix
        if method_name == "starts_with" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.starts_with(prefix) method call
                    return self
                        .generate_string_starts_with_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.ends_with(suffix) method - checks if string ends with suffix
        if method_name == "ends_with" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.ends_with(suffix) method call
                    return self.generate_string_ends_with_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.find(substring) method - finds the byte position of substring
        if method_name == "find" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.find(substring) method call
                    return self.generate_string_find_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.to_uppercase() method - converts string to uppercase
        if method_name == "to_uppercase" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.to_uppercase() method call
                    return self.generate_string_to_uppercase_method(var_name);
                }
            }
        }

        // Special handling for string.to_lowercase() method - converts string to lowercase
        if method_name == "to_lowercase" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.to_lowercase() method call
                    return self.generate_string_to_lowercase_method(var_name);
                }
            }
        }

        // Special handling for string.capitalize() method - capitalizes first character
        if method_name == "capitalize" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.capitalize() method call
                    return self.generate_string_capitalize_method(var_name);
                }
            }
        }

        // Special handling for string.trim() method - removes leading and trailing whitespace
        if method_name == "trim" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.trim() method call
                    return self.generate_string_trim_method(var_name);
                }
            }
        }

        // Special handling for string.trim_start() method - removes leading whitespace
        if method_name == "trim_start" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.trim_start() method call
                    return self.generate_string_trim_start_method(var_name);
                }
            }
        }

        // Special handling for string.trim_end() method - removes trailing whitespace
        if method_name == "trim_end" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.trim_end() method call
                    return self.generate_string_trim_end_method(var_name);
                }
            }
        }

        // Special handling for string.split(separator) method - splits string by separator
        if method_name == "split" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.split(separator) method call
                    return self.generate_string_split_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for string.replace(old, new) method - replaces all occurrences
        if method_name == "replace" {
            // Check if the object is a string variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Basic(types::BasicType::String)) =
                    self.variable_type_map.get(var_name)
                {
                    // This is string.replace(old, new) method call
                    return self.generate_string_replace_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for map.len() method
        if method_name == "len" {
            // Check if the object is a map variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Map(_)) = self.variable_type_map.get(var_name) {
                    // This is map.len() method call
                    return self.generate_map_len_method(var_name);
                }
            }
        }

        // Special handling for map.insert(k, v) method
        if method_name == "insert" {
            // Check if the object is a map variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Map(_)) = self.variable_type_map.get(var_name) {
                    // This is map.insert(k, v) method call
                    return self.generate_map_insert_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for map.contains(k) method
        if method_name == "contains" {
            // Check if the object is a map variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Map(_)) = self.variable_type_map.get(var_name) {
                    // This is map.contains(k) method call
                    return self.generate_map_contains_method(var_name, &method_call.arguments);
                }
            }
        }

        // Special handling for map.remove(k) method
        if method_name == "remove" {
            // Check if the object is a map variable
            if let Expression::Variable(var_name) = &*method_call.object {
                // Get the variable type
                if let Some(Type::Map(_)) = self.variable_type_map.get(var_name) {
                    // This is map.remove(k) method call
                    return self.generate_map_remove_method(var_name, &method_call.arguments);
                }
            }
        }

        // Check if this is a static method call (e.g., Person::new)
        // Static method calls have type names as objects (e.g., Person::new)
        // Instance method calls have variable names as objects (e.g., person.greet)
        let is_static_call = match &*method_call.object {
            Expression::Variable(_name) => {
                // Check if this is a type name (static method) or variable name (instance method)
                // For now, assume that if the method is "new", it's a static method
                // Otherwise, it's an instance method
                method_call.method == "new"
            }
            _ => false,
        };

        // First try to find the method in impl blocks (format: "TypeName.methodName")
        // Prefer using the static type of the receiver to avoid ambiguities
        let mut selected_method_name: Option<String> = None;

        if let Some(object_type) = self.infer_expression_type(&method_call.object) {
            // Prefer resolving through the concrete struct declaration when possible.
            let struct_name_opt = match &object_type {
                // In many non-generic programs, plain type names are parsed as generics.
                // If such a generic matches a known struct, treat it as that struct.
                Type::Generic(name) => {
                    if self.struct_declarations.contains_key(name) {
                        Some(name.clone())
                    } else {
                        None
                    }
                }
                _ => self
                    .resolve_struct_decl_from_type(&object_type)
                    .map(|decl| decl.name.clone()),
            };

            if let Some(struct_name) = struct_name_opt {
                let candidate = format!("{}.{}", struct_name, method_name);
                if self.function_map.contains_key(&candidate) {
                    selected_method_name = Some(candidate);
                }
            }
        }

        // Fallback: scan all structs (keeps legacy behaviour when type information is missing)
        if selected_method_name.is_none() {
            for struct_name in self.struct_declarations.keys() {
                let candidate = format!("{}.{}", struct_name, method_name);
                if self.function_map.contains_key(&candidate) {
                    selected_method_name = Some(candidate);
                    break;
                }
            }
        }

        if let Some(method_name_with_type) = selected_method_name {
            if is_static_call {
                // For static method calls, don't pass receiver
                return Ok(self.generate_static_method_call_with_name(
                    method_call,
                    &method_name_with_type,
                )?);
            } else {
                // For instance method calls, pass receiver as first argument
                return Ok(
                    self.generate_method_call_with_name(method_call, &method_name_with_type)?
                );
            }
        }

        // If not found in impl blocks, try regular function
        let function = if let Some(func) = self.function_map.get(method_name) {
            *func
        } else {
            return Err(CompilerError::internal(&format!(
                "Undefined method: {}",
                method_name
            )));
        };

        // Generate arguments (receiver + method arguments)
        // For static method calls, don't pass receiver
        if is_static_call {
            // Generate arguments (only method arguments, no receiver)
            let mut args = Vec::new();
            for arg in &method_call.arguments {
                let arg_value = self.generate_expression(arg)?;
                args.push(arg_value.into());
            }

            // Call the function
            let result = self
                .builder
                .build_call(function, &args, "static_method_call")?;

            // Return the result
            if function.get_type().get_return_type().is_some() {
                Ok(result.try_as_basic_value().left().unwrap().into())
            } else {
                Ok(self.context.i32_type().const_int(0, false).into())
            }
        } else {
            // For instance method calls, we need to generate the receiver
            // Check if the method expects a pointer type for the first parameter (self)
            let expects_pointer =
                if let Some(first_param) = function.get_type().get_param_types().first() {
                    first_param.is_pointer_type()
                } else {
                    false
                };

            // Generate arguments (receiver + method arguments)
            let receiver_arg: BasicMetadataValueEnum = if expects_pointer {
                // Method expects pointer type (self), pass the pointer directly
                if let Expression::Variable(var_name) = &*method_call.object {
                    if let Some(var_value) = self.variable_map.get(var_name) {
                        if var_value.is_pointer_value() {
                            // Check if this is a reference type or Rc type
                            if let Some(var_type) = self.variable_type_map.get(var_name) {
                                match var_type {
                                    Type::Reference(_) => {
                                        // For reference types, we need to load the address that the reference points to
                                        let ref_ptr = var_value.into_pointer_value();
                                        let ptr_type = self
                                            .context
                                            .i8_type()
                                            .ptr_type(AddressSpace::default());
                                        let target_ptr = self.builder.build_load(
                                            ptr_type,
                                            ref_ptr,
                                            &format!("{}_target", var_name),
                                        )?;

                                        if let BasicValueEnum::PointerValue(actual_ptr) = target_ptr
                                        {
                                            actual_ptr.into()
                                        } else {
                                            return Err(CompilerError::internal(
                                                "Reference should point to a valid address",
                                            ));
                                        }
                                    }
                                    Type::Rc(_) => {
                                        // For Rc types, we need to load the RC block pointer first, then get the data pointer
                                        let rc_ptr = var_value.into_pointer_value();
                                        let rc_block_ptr = self.builder.build_load(
                                            self.context
                                                .i8_type()
                                                .ptr_type(AddressSpace::default()),
                                            rc_ptr,
                                            &format!("{}_rc_block", var_name),
                                        )?;

                                        // Get the data pointer from the RC block (field 2)
                                        let rc_block_type = self.create_rc_block_type();
                                        let data_ptr_field = self.builder.build_struct_gep(
                                            rc_block_type,
                                            rc_block_ptr.into_pointer_value(),
                                            2,
                                            "data_ptr_field",
                                        )?;
                                        let data_ptr = self.builder.build_load(
                                            self.context
                                                .i8_type()
                                                .ptr_type(AddressSpace::default()),
                                            data_ptr_field,
                                            "data_ptr",
                                        )?;

                                        data_ptr.into()
                                    }
                                    _ => {
                                        // Regular type, pass the pointer directly
                                        (*var_value).into()
                                    }
                                }
                            } else {
                                // No type info, assume regular type
                                (*var_value).into()
                            }
                        } else {
                            return Err(CompilerError::internal(
                                "Cannot get pointer of non-pointer receiver",
                            ));
                        }
                    } else {
                        return Err(CompilerError::internal(&format!(
                            "Undefined receiver variable: {}",
                            var_name
                        )));
                    }
                } else {
                    return Err(CompilerError::internal("Cannot get receiver pointer"));
                }
            } else {
                // Method expects value type (self), pass the struct value
                if let Expression::Variable(var_name) = &*method_call.object {
                    if let Some(var_value) = self.variable_map.get(var_name) {
                        if var_value.is_pointer_value() {
                            // Check if this is a reference type or Rc type
                            if let Some(var_type) = self.variable_type_map.get(var_name) {
                                match var_type {
                                    Type::Reference(ref_type) => {
                                        // For reference types, we need to load the address that the reference points to
                                        let ref_ptr = var_value.into_pointer_value();
                                        let ptr_type = self
                                            .context
                                            .i8_type()
                                            .ptr_type(AddressSpace::default());
                                        let target_ptr = self.builder.build_load(
                                            ptr_type,
                                            ref_ptr,
                                            &format!("{}_target", var_name),
                                        )?;

                                        if let BasicValueEnum::PointerValue(actual_ptr) = target_ptr
                                        {
                                            // Now load the actual struct value from the referenced location
                                            let llvm_type = self.nrc_type_to_llvm_type(&Some(
                                                *ref_type.referenced_type.clone(),
                                            ))?;
                                            let loaded_value = self.builder.build_load(
                                                llvm_type,
                                                actual_ptr,
                                                "loaded_receiver",
                                            )?;
                                            loaded_value.into()
                                        } else {
                                            return Err(CompilerError::internal(
                                                "Reference should point to a valid address",
                                            ));
                                        }
                                    }
                                    Type::Rc(rc_type) => {
                                        // For Rc types, we need to load the RC block pointer first, then get the data pointer
                                        let rc_ptr = var_value.into_pointer_value();
                                        let rc_block_ptr = self.builder.build_load(
                                            self.context
                                                .i8_type()
                                                .ptr_type(AddressSpace::default()),
                                            rc_ptr,
                                            &format!("{}_rc_block", var_name),
                                        )?;

                                        // Get the data pointer from the RC block (field 2)
                                        let rc_block_type = self.create_rc_block_type();
                                        let data_ptr_field = self.builder.build_struct_gep(
                                            rc_block_type,
                                            rc_block_ptr.into_pointer_value(),
                                            2,
                                            "data_ptr_field",
                                        )?;
                                        let data_ptr = self.builder.build_load(
                                            self.context
                                                .i8_type()
                                                .ptr_type(AddressSpace::default()),
                                            data_ptr_field,
                                            "data_ptr",
                                        )?;

                                        // Now load the actual struct value from the data pointer
                                        let llvm_type = self.nrc_type_to_llvm_type(&Some(
                                            *rc_type.inner_type.clone(),
                                        ))?;
                                        let typed_data_ptr = self
                                            .builder
                                            .build_bitcast(
                                                data_ptr.into_pointer_value(),
                                                llvm_type.ptr_type(AddressSpace::default()),
                                                "typed_data_ptr",
                                            )?
                                            .into_pointer_value();
                                        let loaded_value = self.builder.build_load(
                                            llvm_type,
                                            typed_data_ptr,
                                            "loaded_receiver",
                                        )?;
                                        loaded_value.into()
                                    }
                                    _ => {
                                        // Regular type, load the struct value from the pointer
                                        let llvm_type =
                                            self.nrc_type_to_llvm_type(&Some(var_type.clone()))?;
                                        let loaded_value = self.builder.build_load(
                                            llvm_type,
                                            var_value.into_pointer_value(),
                                            "loaded_receiver",
                                        )?;
                                        loaded_value.into()
                                    }
                                }
                            } else {
                                // No type info, fallback to generate_expression
                                let receiver = self.generate_expression(&method_call.object)?;
                                receiver.into()
                            }
                        } else {
                            return Err(CompilerError::internal(
                                "Cannot get value of non-pointer receiver",
                            ));
                        }
                    } else {
                        return Err(CompilerError::internal(&format!(
                            "Undefined receiver variable: {}",
                            var_name
                        )));
                    }
                } else {
                    // Not a variable, use generate_expression
                    let receiver = self.generate_expression(&method_call.object)?;
                    receiver.into()
                }
            };

            // Generate method arguments
            let mut args = vec![receiver_arg];
            for arg in &method_call.arguments {
                let arg_value = self.generate_expression(arg)?;
                args.push(arg_value.into());
            }

            // Call the function
            let result = self.builder.build_call(function, &args, "method_call")?;

            // Return the result
            if function.get_type().get_return_type().is_some() {
                Ok(result.try_as_basic_value().left().unwrap().into())
            } else {
                Ok(self.context.i32_type().const_int(0, false).into())
            }
        }
    }

    fn generate_trait_object_method_call(
        &mut self,
        trait_name: &str,
        method_call: &MethodCallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        let object_value = self.generate_expression(&method_call.object)?;
        self.generate_trait_object_method_call_from_value(trait_name, method_call, object_value)
    }

    fn generate_trait_object_method_call_from_value(
        &mut self,
        trait_name: &str,
        method_call: &MethodCallExpr,
        object_value: BasicValueEnum<'ctx>,
    ) -> Result<BasicValueEnum<'ctx>> {
        let trait_decl = self
            .trait_declarations
            .get(trait_name)
            .cloned()
            .ok_or_else(|| {
                CompilerError::internal(&format!("Unknown trait '{}'", trait_name))
            })?;
        let method_index = trait_decl
            .methods
            .iter()
            .position(|m| m.name == method_call.method)
            .ok_or_else(|| {
                CompilerError::internal(&format!(
                    "Trait '{}' has no method '{}'",
                    trait_name, method_call.method
                ))
            })?;
        let trait_method = trait_decl.methods[method_index].clone();
        let total_methods = trait_decl.methods.len();

        let trait_struct = self.ensure_trait_object_type(trait_name);
        let trait_ptr = match object_value {
            BasicValueEnum::PointerValue(ptr) => self
                .builder
                .build_bitcast(
                    ptr,
                    trait_struct.ptr_type(AddressSpace::default()),
                    "trait_obj_ptr",
                )?
                .into_pointer_value(),
            BasicValueEnum::StructValue(struct_val) => {
                let temp = self.builder.build_alloca(trait_struct, "trait_obj_tmp")?;
                self.builder.build_store(temp, struct_val)?;
                temp
            }
            _ => {
                return Err(CompilerError::internal(
                    "Trait object receiver must be reference",
                ))
            }
        };

        let i8_ptr = self.context.i8_type().ptr_type(AddressSpace::default());
        let data_field = self
            .builder
            .build_struct_gep(trait_struct, trait_ptr, 0, "trait_data_field")?;
        let data_ptr = self
            .builder
            .build_load(i8_ptr, data_field, "trait_data_ptr")?
            .into_pointer_value();

        let vtable_field = self
            .builder
            .build_struct_gep(trait_struct, trait_ptr, 1, "trait_vtable_field")?;
        let raw_vtable_ptr = self
            .builder
            .build_load(i8_ptr, vtable_field, "trait_vtable_ptr")?
            .into_pointer_value();
        let vtable_type = self.ensure_trait_vtable_type(trait_name, total_methods);
        let vtable_ptr = self
            .builder
            .build_bitcast(
                raw_vtable_ptr,
                vtable_type.ptr_type(AddressSpace::default()),
                "trait_vtable",
            )?
            .into_pointer_value();

        let method_ptr_ptr = self.builder.build_struct_gep(
            vtable_type,
            vtable_ptr,
            method_index as u32,
            "trait_method_ptr",
        )?;
        let method_ptr_i8 = self
            .builder
            .build_load(i8_ptr, method_ptr_ptr, "trait_method_fn")?
            .into_pointer_value();

        let fn_type = self.trait_method_llvm_type(&trait_method)?;
        let fn_ptr = self
            .builder
            .build_bitcast(
                method_ptr_i8,
                fn_type.ptr_type(AddressSpace::default()),
                "trait_method_fn_cast",
            )?
            .into_pointer_value();

        let mut call_args: Vec<BasicMetadataValueEnum> = vec![data_ptr.into()];
        let param_offset = if trait_method
            .parameters
            .first()
            .map(|p| p.name.as_str() == "self")
            .unwrap_or(false)
        {
            1
        } else {
            0
        };

        for (arg_expr, param) in method_call
            .arguments
            .iter()
            .zip(trait_method.parameters.iter().skip(param_offset))
        {
            let arg_value = self.generate_expression(arg_expr)?;
            let coerced = self.coerce_value_to_type(
                arg_value,
                self.infer_expression_type(arg_expr).as_ref(),
                &param.param_type,
            )?;
            call_args.push(coerced.into());
        }

        let call_site =
            self.builder
                .build_indirect_call(fn_type, fn_ptr, &call_args, "trait_call")?;
        if fn_type.get_return_type().is_none() {
            Ok(self.context.i32_type().const_int(0, false).into())
        } else {
            let result = call_site.try_as_basic_value().left().unwrap();
            Ok(result)
        }
    }

    fn generate_rc_trait_method_call(
        &mut self,
        trait_name: &str,
        method_call: &MethodCallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        let rc_value = self.generate_expression(&method_call.object)?;
        let (rc_ptr, vtable_ptr) =
            self.extract_trait_rc_components(trait_name, rc_value)?;

        // Load data pointer from rc block
        let rc_block_type = self.create_rc_block_type();
        let data_ptr_field = self
            .builder
            .build_struct_gep(rc_block_type, rc_ptr, 2, "trait_rc_data_field")?;
        let data_ptr = self.builder.build_load(
            self.context.i8_type().ptr_type(AddressSpace::default()),
            data_ptr_field,
            "trait_rc_data_ptr",
        )?;

        let trait_struct = self.ensure_trait_object_type(trait_name);
        let alloca = self.builder.build_alloca(trait_struct, "trait_obj_from_rc")?;
        let data_field = self
            .builder
            .build_struct_gep(trait_struct, alloca, 0, "trait_obj_data")?;
        self.builder.build_store(data_field, data_ptr)?;
        let vtable_field = self
            .builder
            .build_struct_gep(trait_struct, alloca, 1, "trait_obj_vtable")?;
        self.builder.build_store(vtable_field, vtable_ptr)?;

        self.generate_trait_object_method_call_from_value(
            trait_name,
            method_call,
            alloca.into(),
        )
    }

    fn generate_rc_downgrade_method_call(
        &mut self,
        rc_type: &crate::ast::types::RcType,
        method_call: &MethodCallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        if !method_call.arguments.is_empty() {
            return Err(CompilerError::internal(
                "Rc::downgrade() does not take any arguments",
            ));
        }

        let object_value = self.generate_expression(&method_call.object)?;
        if let Some(trait_name) = self.trait_name_from_type(&rc_type.inner_type) {
            let (rc_ptr, vtable_ptr) =
                self.extract_trait_rc_components(&trait_name, object_value)?;
            self.generate_weak_increment(rc_ptr.into())?;
            self.build_trait_weak_value(&trait_name, rc_ptr, vtable_ptr)
        } else {
            let rc_ptr = self.rc_block_pointer_from_value(object_value, rc_type)?;
            self.generate_weak_increment(rc_ptr.into())?;
            Ok(rc_ptr.into())
        }
    }

    fn generate_weak_lock_method_call(
        &mut self,
        weak_type: &crate::ast::types::WeakType,
        method_call: &MethodCallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        if !method_call.arguments.is_empty() {
            return Err(CompilerError::internal(
                "Weak::lock() does not take any arguments",
            ));
        }

        let option_type = crate::ast::types::OptionType {
            some_type: Box::new(Type::Rc(crate::ast::types::RcType {
                inner_type: weak_type.inner_type.clone(),
                location: weak_type.location,
            })),
            location: method_call.location,
        };

        let option_llvm_type = match self.get_option_llvm_type(&option_type)? {
            BasicTypeEnum::StructType(st) => st,
            _ => {
                return Err(CompilerError::internal(
                    "Option type must be represented as a struct",
                ))
            }
        };
        let option_alloca = self
            .builder
            .build_alloca(option_llvm_type, "weak_lock_option")?;

        let object_value = self.generate_expression(&method_call.object)?;
        let trait_name = self.trait_name_from_type(&weak_type.inner_type);
        let mut trait_info: Option<(String, inkwell::values::PointerValue<'ctx>)> = None;
        let weak_ptr = if let Some(trait_name) = trait_name.clone() {
            let (ptr, vtable_ptr) =
                self.extract_trait_weak_components(&trait_name, object_value)?;
            trait_info = Some((trait_name, vtable_ptr));
            ptr
        } else if let BasicValueEnum::PointerValue(ptr) = object_value {
            ptr
        } else {
            return Err(CompilerError::internal(
                "Weak<T> value must be representable as a pointer",
            ));
        };

        let rc_ptr_value = self.generate_weak_lock(weak_ptr.into())?;
        let rc_ptr = rc_ptr_value.into_pointer_value();

        let is_null = self.builder.build_is_null(rc_ptr, "weak_lock_is_null")?;

        let current_fn = self.current_function.ok_or_else(|| {
            CompilerError::internal("Weak::lock() used outside of a function")
        })?;
        let some_block = self
            .context
            .append_basic_block(current_fn, "weak_lock_some");
        let none_block = self
            .context
            .append_basic_block(current_fn, "weak_lock_none");
        let merge_block = self
            .context
            .append_basic_block(current_fn, "weak_lock_merge");

        self.builder
            .build_conditional_branch(is_null, none_block, some_block)?;

        // Some branch
        self.builder.position_at_end(some_block);
        let rc_value = if let Some((trait_name, vtable_ptr)) = &trait_info {
            self.build_trait_rc_value(trait_name, rc_ptr, *vtable_ptr)?
        } else {
            rc_ptr.into()
        };
        let some_option = self.create_option_value(0, Some(rc_value), &option_type)?;
        self.builder.build_store(option_alloca, some_option)?;
        self.builder.build_unconditional_branch(merge_block)?;

        // None branch
        self.builder.position_at_end(none_block);
        let none_option = self.create_option_value(1, None, &option_type)?;
        self.builder.build_store(option_alloca, none_option)?;
        self.builder.build_unconditional_branch(merge_block)?;

        // Merge
        self.builder.position_at_end(merge_block);
        let result = self
            .builder
            .build_load(option_llvm_type, option_alloca, "weak_lock_result")?;
        Ok(result.into())
    }

}
